#include <NoteTrackRenderer.h>

namespace pp
{
    NoteTrackRenderer::NoteTrackRenderer()
        : mColor(ne::Color::ORANGE),
          mpDynamicGeometry(0)
    {
    }

    bool NoteTrackRenderer::build(ne::MIDITrack *pTrack)
    {
        destroy();

        if (!pTrack || !pTrack->hasNotes()) return false;

        mNoteTrack.build(pTrack);

        if (mNoteTrack.getNumNotes() > 0)
        {
            mpDynamicGeometry = new ne::DynamicGeometry(ne::PT_TRIANGLES);
        }

        return true;
    }

    bool NoteTrackRenderer::update(const double startTicks, const double endTicks, const double deltaY)
    {
        if (!mpDynamicGeometry) return false;

        mpDynamicGeometry->beginGeometry();

        for (ne::MIDINoteListConstIterator it=mNoteTrack.begin(); it!=mNoteTrack.end(); ++it)
        {
            ne::MIDINote *pNote = (*it);

            if (pNote->absoluteTicks > endTicks) break;

            if (pNote->absoluteTicks + pNote->duration >= startTicks)
            {
                double s = std::max(startTicks, pNote->absoluteTicks);
                double e = std::min(endTicks, pNote->absoluteTicks + pNote->duration);
                double y = (s - startTicks) * deltaY - 360;
                double h = std::max(e - s, 1.0) * deltaY;

                int m = pNote->pitch / 12;
                int bw = pNote->pitch % 12;
                double x = NoteOffset[12] * m + NoteOffset[bw] - 940;
                double w = 11;
                ne::Color c = mColor;
                if (ne::PianoKeyboard::IsBlackKey(ne::MIDIPitchType(pNote->pitch)))
                {
                    w = 5;
                    c = mColor * 0.75f;
                    c.a = 1.0f;
                }

                ne::uint32_t index = mpDynamicGeometry->getVertexCount();

                mpDynamicGeometry->addPosition(ne::Vector3(x - w, y, 0));
                mpDynamicGeometry->addColor(c);
                mpDynamicGeometry->addPosition(ne::Vector3(x - w, y + h, 0));
                mpDynamicGeometry->addColor(c);
                mpDynamicGeometry->addPosition(ne::Vector3(x + w, y, 0));
                mpDynamicGeometry->addColor(c);
                mpDynamicGeometry->addPosition(ne::Vector3(x + w, y + h, 0));
                mpDynamicGeometry->addColor(c);

                mpDynamicGeometry->addIndex(index);
                mpDynamicGeometry->addIndex(index + 3);
                mpDynamicGeometry->addIndex(index + 1);
                mpDynamicGeometry->addIndex(index);
                mpDynamicGeometry->addIndex(index + 2);
                mpDynamicGeometry->addIndex(index + 3);
            }
        }

        mpDynamicGeometry->endGeometry();

        /* TODO: Test DynamicGeometry Index
        mpDynamicGeometry->beginIndex();
        ne::uint32_t vertexCount = mpDynamicGeometry->getVertexCount();
        for (ne::uint32_t i=0; i<vertexCount; i+=4)
        {
            mpDynamicGeometry->addIndex(i);
            mpDynamicGeometry->addIndex(i + 3);
            mpDynamicGeometry->addIndex(i + 1);
            mpDynamicGeometry->addIndex(i);
            mpDynamicGeometry->addIndex(i + 2);
            mpDynamicGeometry->addIndex(i + 3);
        }
        mpDynamicGeometry->endIndex();
        */

        return true;
    }

    bool NoteTrackRenderer::render()
    {
        if (mpDynamicGeometry)
        {
            ne::VertexDataPtr vertexData = mpDynamicGeometry->getVertexData();
            ne::IndexDataPtr indexData = mpDynamicGeometry->getIndexData();

            if (vertexData.isNull() || indexData.isNull()) return false;

            /*
            ne::PrimitiveDeclaration pd;
            pd.setPrimitiveType(ne::PT_TRIANGLES);
            pd.addVertexAttribute(vertexData->getAttribute(ne::VAS_POSITION));
            pd.addVertexAttribute(vertexData->getAttribute(ne::VAS_COLOR));
            pd.addIndexAttribute(indexData->getAttribute());

            return ne::RenderSystem::GetSingleton().render(pd);
            */

            ne::VertexAttributePtr va;

            va = vertexData->getAttribute(ne::VAS_POSITION);
            if (va.notNull())
            {
                glBindBuffer(GL_ARRAY_BUFFER, va->getSource());
                glVertexPointer(va->getGLDataCount(), va->getGLDataType(), va->getStride(), va->getOffsetPointer());
                glEnableClientState(GL_VERTEX_ARRAY);
            }

            va = vertexData->getAttribute(ne::VAS_COLOR);
            if (va.notNull())
            {
                glBindBuffer(GL_ARRAY_BUFFER, va->getSource());
                glColorPointer(va->getGLDataCount(), va->getGLDataType(), va->getStride(), va->getOffsetPointer());
                glEnableClientState(GL_COLOR_ARRAY);
            }

            if (indexData.notNull())
            {
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexData->getSource());
                glIndexPointer(indexData->getGLDataType(), indexData->getAttributeSize(), indexData->getOffsetPointer());
                glEnableClientState(GL_INDEX_ARRAY);
                glDrawElements(indexData->getPrimitiveType(), indexData->getCount(), indexData->getGLDataType(), indexData->getOffsetPointer());
            }

            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_VERTEX_ARRAY);
            glDisableClientState(GL_INDEX_ARRAY);

            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
            glBindBuffer(GL_ARRAY_BUFFER, 0);

            return true;
        }
        return false;
    }

    void NoteTrackRenderer::destroy()
    {
        delete mpDynamicGeometry;
        mNoteTrack.destroyAllNotes();
    }

    NoteTrackRenderer::~NoteTrackRenderer()
    {
        destroy();
    }
}
